package com.javafactroy.kunlong.common.utils;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import jodd.util.StringTemplateParser;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;

import static org.springframework.util.StringUtils.isEmpty;

public final class CommonUtils {
    public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss";

    //默认去掉“-”
    public static String getUUID(boolean flag) {
        String s = UUID.randomUUID().toString();
        if (flag) {
            return s.replace("-", "");
        }

        return s;
    }

    public static String today(){
        return DateUtil.formatDateTime(new Date());
    }

    public static String getObjectId() {

        return "";//new ObjectId().toString();
    }

//    public byte[] toByteArray(String v, int len) {
//        ByteBuffer buffer = ByteBuffer.allocate(len);
//        //this.putToByteBuffer(buffer);
//        return buffer.array();
//    }

    /**
     * 获取IP地址
     * <p>
     * 使用Nginx等反向代理软件， 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，X-Forwarded-For中第一个非unknown的有效IP字符串，则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        return ip;
    }

    public static <T> T parseObject(String text, Class<T> clazz) {
        return JSON.parseObject(text, clazz);
    }

    public static String toJSONStringSkipNull(Object o) {
        return JSONObject.toJSONString(o, SerializerFeature.SkipTransientField, SerializerFeature.PrettyFormat);

    }

    public String toJsonPrettyStr(Object o){
        return JSONUtil.toJsonPrettyStr(o);
    }

    public static String toJSONString(Object o) {
        return JSONObject.toJSONString(o, SerializerFeature.IgnoreErrorGetter, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.SkipTransientField, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue);

    }

    public static String quatStr(String value){
        return "'"+value+"'";
    }

    public static String toJSONStringPretty(Object o) {
        return JSONObject.toJSONString(o, SerializerFeature.IgnoreErrorGetter, SerializerFeature.PrettyFormat, SerializerFeature.SkipTransientField, SerializerFeature.WriteMapNullValue);

    }

    public static Object invokeMethod(String clsName, String mName, Class[] parameterTypes, Object... args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
        Class cls = Class.forName(clsName);
        Object o = cls.newInstance();
        Method m = cls.getDeclaredMethod(mName, parameterTypes);
        return m.invoke(o, args);  // Type type = m.getGenericReturnType();
    }

    public static Object invokeMethod_try(String clsName, String mName, Class[] parameterTypes, Object... args) throws InvocationTargetException, NoSuchMethodException {
        try {
            return invokeMethod(clsName, mName, parameterTypes, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            throw e;
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            throw e;
        }
        return null;
    }


    public static long dateDiffDays(Date sdate, Date edate) {

        return (sdate.getTime() - edate.getTime()) / 24 / 1000 / 60 / 60;
    }

    public static Date dateAddDays(Date date, int days) {
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(date);
        //rightNow.add(Calendar.YEAR,-1);//日期减1年
        //rightNow.add(Calendar.MONTH,3);//日期加3个月
        rightNow.add(Calendar.DAY_OF_YEAR, days);//日期加
        return rightNow.getTime();
    }

    //http://ip.taobao.com/service/getIpInfo.php?ip=111.222.241.139
    /*input :ip
    output:
    {
	"code":0,
	"data":{
		"area":"",
		"country":"中国",
		"isp_id":"100076",
		"city":"深圳",
		"ip":"111.222.241.139",
		"isp":"天威",
		"county":"XX",
		"region_id":"440000",
		"area_id":"",
		"county_id":"xx",
		"region":"广东",
		"country_id":"CN",
		"city_id":"440300"
	}
    }   */


    public static String transDatetime(Date d) {
        if (d == null) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(d);
    }

    public static String transDate(Date d) {
        if (d == null) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(d);
    }


    public static BigDecimal newBigDecimal(float value) {
        return new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal newBigDecimal(BigDecimal value) {
        return value.setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal newBigDecimal(double value) {
        return new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal newBigDecimal(int value) {
        return new BigDecimal(value).setScale(2, BigDecimal.ROUND_HALF_UP);
    }


    public static BigDecimal newBigDecimal(int newScale, float value) {
        return new BigDecimal(value).setScale(newScale, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal newBigDecimal(int newScale, BigDecimal value) {
        return value.setScale(newScale, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal newBigDecimal(int newScale, double value) {
        return new BigDecimal(value).setScale(newScale, BigDecimal.ROUND_HALF_UP);
    }

    public static BigDecimal newBigDecimal(int newScale, int value) {
        return new BigDecimal(value).setScale(newScale, BigDecimal.ROUND_HALF_UP);
    }

    public static Date getFirstDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();

    }

    public static Date getLastDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.MONTH, 1);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        return calendar.getTime();
    }
    //Gson gson = new Gson();

    static Gson gson = new GsonBuilder().setLenient()// json宽松
            .enableComplexMapKeySerialization()//支持Map的key为复杂对象的形式
            .serializeNulls() //智能null
            .setDateFormat(DEFAULT_DATE_PATTERN).setPrettyPrinting()// 调教格式
            .disableHtmlEscaping() //默认是GSON把HTML 转义的
            .create();

    public static String toJsonStr(Object o) {

        return gson.toJson(o);
    }

    public static String object2Xml(Object o, String root) {
        JSONConfig jsonConfig = new JSONConfig();
        jsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        cn.hutool.json.JSON json = JSONUtil.parse(o, jsonConfig);
        String xml = JSONUtil.toXmlStr(json);
        return StrUtil.format("<{}>{}</{}>", root, xml, root);
    }

    public static String parseTemplate(String tmpl, Map<String, String> params) {
//        String template = "Hello ${foo}. ${foo} Today is ${dayName}.";
//
//        // prepare data
//        Map<String, String> map = new HashMap<String, String>();
//        map.put("foo", "Jodd");
//        map.put("dayName", "Sunday");
        Function<String, String> macroResolver = (p) -> {
            return params.get(p);
        };
        // parse
        StringTemplateParser parser = new StringTemplateParser(macroResolver);
        String result = parser.apply(tmpl);

        // result == "Hello Jodd. Today is Sunday."
        //log.info("{}",result);
        return result;
    }
}

